<cfcomponent name="NaNoWriMoGateway" extends="Gateway" hint="Proxy to NaNoWriMo services" namespace="com.nowrists" output="false">
	<cffunction name="UserInfo" access="remote" output="false" returntype="query">
		<cfargument name="UID" type="numeric" required="true">
		<cfset var NeedToFetch=true>
		<cfset var Data="">
		<cfset var i="">
		<cfset var ColName="">
		<cfset var ColType="">
		<cfset var Buddy="">
		<cfset IsValidXML=True>
		<cflock name="NaNoWriMoGateway_UserInfo_#Arguments.UID#" type="exclusive" timeout="30">
			<cfquery datasource="#Variables.DSN#" name="FindUID">
			SELECT uid, username, photo, website AS homepage, postcount, region, winner, donor, wordcount, samplecount, noveltitle, daily, location, age, yearsdone, yearswon, genre, fetch_date AS FetchDate, NULL AS JoinDate
			FROM nws_nano_userinfo
			WHERE (uid = <cfqueryparam cfsqltype="cf_sql_numeric" value="#Arguments.UID#">)
			</cfquery>
			<cfif (FindUID.RecordCount EQ 1) AND IsDate(FindUID.FetchDate) AND (DateAdd("h",1,FindUID.FetchDate) GTE Now())>
				<cfset NeedToFetch=false>
			</cfif>
			<cfif NeedToFetch>
				<cftry>
					<cfhttp method="get" url="http://www.nanowrimo.org/usergenerator.php?uid=#Arguments.UID#" useragent="Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)"></cfhttp>
					<cfset Data=ReReplaceNoCase(CFHTTP.FileContent,"&&+","&amp;&amp;","ALL")>
					<cfset Data=ReReplaceNoCase(Data,"&##[0-9a-f]+;","","ALL")>
					<cfset Data=ReReplaceNoCase(Data,"&([^a##])","&amp;\1","ALL")>
					<cftry>
						<cfset Data=XMLParse(Data)>
						<cfcatch>
							<cfdump var="#CFHTTP#">
							<cfdump var="#CFCatch#">
							<cfset IsValidXML=False>
						</cfcatch>
					</cftry>
					<cfif IsValidXML>
						<cfif StructKeyExists(Data,"data")>
							<cfif FindUID.RecordCount EQ 0>
								<cfquery datasource="#Variables.DSN#">
								INSERT INTO nws_nano_userinfo (uid, fetch_date, xml_source)
								VALUES (
									<cfqueryparam cfsqltype="cf_sql_integer" value="#Arguments.UID#">,
									NOW(),
									<cfqueryparam cfsqltype="cf_sql_longvarchar" value="#Trim(Data)#">
								)
								</cfquery>
							</cfif>
							<cfquery datasource="#Variables.DSN#">
							UPDATE nws_nano_userinfo
							SET fetch_date = NOW(),
								<cfif StructKeyExists(Data.Data,"user")>
									<cfif StructKeyExists(Data.Data.User.XmlAttributes,"name") AND (Trim(Data.Data.User.XmlAttributes.name) NEQ "")>username = <cfqueryparam cfsqltype="cf_sql_varchar" value="#Trim(Data.Data.User.XmlAttributes.name)#">,</cfif>
									<cfif StructKeyExists(Data.Data.User.XmlAttributes,"photo") AND (Trim(Data.Data.User.XmlAttributes.photo) NEQ "")>photo = <cfqueryparam cfsqltype="cf_sql_varchar" value="#Trim(Data.Data.User.XmlAttributes.photo)#">,</cfif>
									<cfif StructKeyExists(Data.Data.User.XmlAttributes,"website") AND (Trim(Data.Data.User.XmlAttributes.website) NEQ "")>website = <cfqueryparam cfsqltype="cf_sql_varchar" value="#Trim(Data.Data.User.XmlAttributes.website)#">,</cfif>
									<cfif StructKeyExists(Data.Data.User,"postcount") AND IsNumeric(Data.Data.User.postcount.XmlText)>postcount = <cfqueryparam cfsqltype="cf_sql_integer" value="#Val(Data.Data.User.PostCount.XmlText)#">,</cfif>
									<cfif StructKeyExists(Data.Data.User,"wordcount") AND IsNumeric(Data.Data.User.wordcount.XmlText)>wordcount = <cfqueryparam cfsqltype="cf_sql_integer" value="#Val(Data.Data.User.WordCount.XmlText)#">,</cfif>
									<cfif StructKeyExists(Data.Data.User,"samplecount") AND IsNumeric(Data.Data.User.samplecount.XmlText)>samplecount = <cfqueryparam cfsqltype="cf_sql_integer" value="#Val(Data.Data.User.SampleCount.XmlText)#">,</cfif>
									<cfif StructKeyExists(Data.Data.User,"region") AND (Trim(Data.Data.User.region.XmlText) NEQ "")>region = <cfqueryparam cfsqltype="cf_sql_varchar" value="#Trim(Data.Data.User.Region.XmlText)#">,</cfif>
									<cfif StructKeyExists(Data.Data.User,"novel") AND StructKeyExists(Data.Data.User.Novel.XmlAttributes,"title") AND (Trim(Data.Data.User.Novel.XmlAttributes.Title) NEQ "")>noveltitle = <cfqueryparam cfsqltype="cf_sql_varchar" value="#Trim(Data.Data.User.Novel.XmlAttributes.Title)#">,</cfif>
									<cfif StructKeyExists(Data.Data.User,"winner") AND (ListFind("true,false",Trim(Data.Data.User.Winner.XmlText)) GT 0)>winner = <cfqueryparam cfsqltype="cf_sql_integer" value="#DecrementValue(ListFind('false,true',Trim(Data.Data.User.Winner.XmlText)))#">,</cfif>
									<cfif StructKeyExists(Data.Data.User,"donor") AND (ListFind("true,false",Trim(Data.Data.User.Donor.XmlText)) GT 0)>donor = <cfqueryparam cfsqltype="cf_sql_integer" value="#DecrementValue(ListFind('false,true',Trim(Data.Data.User.Donor.XmlText)))#">,</cfif>
									<cfif StructKeyExists(Data.Data.User,"bio")>
										<cfloop from="1" to="#ArrayLen(Data.Data.User.Bio.XmlChildren)#" index="i">
											<cfif StructKeyExists(Data.Data.User.Bio.XmlChildren[i].XmlAttributes,"Label") AND StructKeyExists(Data.Data.User.Bio.XmlChildren[i].XmlAttributes,"Value") AND (Trim(Data.Data.User.Bio.XmlChildren[i].XmlAttributes.Value) NEQ "")>
												<cfset ColName="">
												<cfset ColType="cf_sql_varchar">
												<cfswitch expression="#Data.Data.User.Bio.XmlChildren[i].XmlAttributes.Label#">
													<cfcase value="Years done NaNo"><cfset ColName="yearsdone"></cfcase>
													<cfcase value="Years won NaNo"><cfset ColName="yearswon"></cfcase>
													<cfcase value="Age"><cfset ColName="age"><cfset ColType="cf_sql_integer"></cfcase>
													<cfcase value="Location"><cfset ColName="location"></cfcase>
													<cfcase value="Genre"><cfset ColName="genre"></cfcase>
												</cfswitch>
												<cfif (ColName NEQ "")>
													#ColName# = <cfqueryparam cfsqltype="#ColType#" value="#Trim(Data.Data.User.Bio.XmlChildren[i].XmlAttributes.Value)#">,
												</cfif>
											</cfif>
										</cfloop>
									</cfif>
									<cfif StructKeyExists(Data.Data.User,"daily") AND (Trim(Data.Data.User.Daily.XmlText) NEQ "")>daily = <cfqueryparam cfsqltype="cf_sql_varchar" value="#Trim(Data.Data.User.Daily.XmlText)#">,</cfif>
								</cfif>
							  xml_source = <cfqueryparam cfsqltype="cf_sql_longvarchar" value="#Trim(Data)#">
							WHERE (uid = <cfqueryparam cfsqltype="cf_sql_integer" value="#Arguments.UID#">)
							</cfquery>
							<cfif StructKeyExists(Data.Data,"user") AND StructKeyExists(Data.Data.User,"buddies") AND (ArrayLen(Data.Data.User.Buddies.XmlChildren) GT 0)>
								<cfquery datasource="#Variables.DSN#">
								DELETE FROM nws_user_buddies
								WHERE (uid = <cfqueryparam cfsqltype="cf_sql_integer" value="#Arguments.UID#">)
								</cfquery>
								<cfloop from="1" to="#ArrayLen(Data.Data.User.Buddies.XmlChildren)#" index="i">
									<cfset Buddy=Data.Data.User.Buddies.XmlChildren[i]>
									<cfif (Buddy.XmlName EQ "buddy") AND StructKeyExists(Buddy.XmlAttributes,"uid")>
										<cfquery datasource="#Variables.DSN#">
										INSERT INTO nws_user_buddies (uid, buddy_name, buddy_uid, wordcount, winner, photo, fetch_date)
										VALUES (
											<cfqueryparam cfsqltype="cf_sql_integer" value="#Arguments.UID#">,
											<cfloop list="name:cf_sql_varchar,uid:cf_sql_integer,wordcount:cf_sql_integer,winner:cf_sql_varchar,photo:cf_sql_varchar" index="ColName">
												<cfif StructKeyExists(Buddy.XmlAttributes,ListFirst(ColName,":"))>
													<cfqueryparam cfsqltype="#ListRest(ColName,':')#" value="#Trim(Buddy.XmlAttributes[ListFirst(ColName,':')])#">
												<cfelse>
												NULL
												</cfif>,
											</cfloop>
											NOW()
										)
										</cfquery>
									</cfif>
								</cfloop>
							</cfif>
							<cfquery datasource="#Variables.DSN#" name="FindUID">
							SELECT uid, username, photo, website, postcount, region, winner, donor, wordcount, samplecount, noveltitle, daily, location, age, yearsdone, yearswon, genre, fetch_date AS FetchDate
							FROM nws_nano_userinfo
							WHERE (uid = <cfqueryparam cfsqltype="cf_sql_numeric" value="#Arguments.UID#">)
							</cfquery>
						</cfif>
					<cfelse>
						<cfabort showerror="NaNo did not return XML data">
					</cfif>
				<cfcatch>
					<cfdump var="#CFCatch#">
					<cfabort>
				</cfcatch>
				</cftry>
			</cfif>
		</cflock>
		<cfreturn FindUID>
	</cffunction>
	<cffunction name="UserFriendsAsQuery" access="public" output="true" returntype="query">
		<cfargument name="UID" type="numeric" required="true">
		<cfargument name="Count" type="numeric" required="false" default="2">
		<cfset var Ret="">
		<cfquery name="Ret" datasource="#Variables.DSN#" maxrows="#Arguments.Count#">
		SELECT b.buddy_name AS BuddyName, b.buddy_uid AS BuddyUID, b.wordcount AS BuddyWordCount, CASE WHEN COALESCE(b.winner,0) = 1 THEN 'Winner!' END AS BuddyWinner, f.noveltitle AS BuddyNovelTitle
		FROM nws_user_buddies AS b
		  INNER JOIN nws_nano_userinfo AS u ON (b.uid = u.uid)
		  LEFT OUTER JOIN nws_nano_userinfo AS f ON (b.buddy_uid = f.uid)
		WHERE (b.uid = <cfqueryparam cfsqltype="cf_sql_numeric" value="#Arguments.UID#">)
		ORDER BY ABS(b.wordcount - u.wordcount), RAND()
		LIMIT <cfqueryparam cfsqltype="cf_sql_numeric" value="#Arguments.Count#">
		</cfquery>
		<cfreturn Ret>
	</cffunction>
	<cffunction name="FindUserAsQuery" access="remote" output="true" returntype="query">
		<cfargument name="Username" type="string" required="true" >
		<cfargument name="Debug" type="boolean" required="false" default="false">
		<cfset var UName=REReplaceNoCase(Arguments.Username, "[^-a-zA-Z0-9_@. ]","","ALL")>
		<cfset var Result=QueryNew("Username,UID,NovelTitle,HomePage,Location,JoinDate,PostCount,Donor")>
		<cfset var i=0>
		<cfset var j=0>
		<cfset var m=0>
		<cfset var Content="">
		<cfset var ua="">
		<cfset var PerfectMatch=0>
		<cfset var Extra=0>
		<cfset var url="http://www.nanowrimo.org/modules/xoopsmembers/index.php?op=submit&matchfield=uname&matchcontent=" & URLEncodedFormat(UName)>
		<cfquery datasource="#Variables.DSN#" name="FindUsername">
		SELECT uid, username, photo, website AS homepage, postcount, region, winner, donor, wordcount, samplecount, noveltitle, daily, location, age, yearsdone, yearswon, genre, fetch_date AS FetchDate, NULL AS JoinDate
		FROM nws_nano_userinfo
		WHERE (username = <cfqueryparam cfsqltype="cf_sql_varchar" value="#Arguments.Username#">)
		</cfquery>
		<cfif FindUserName.RecordCount EQ 1>
			<cfreturn FindUsername>
		</cfif>
		<cfset ua=CreateObject("component","org.rickosborne.util.UserAgent").init()>
		<cfset Content=ua.Fetch("GET",url)>
		<cfset Content=REReplaceNoCase(Content,'.*<div id="contentWide"','','ALL')>
		<cfset Content=REReplaceNoCase(Content,'</table>.*','</table>','ALL')>
		<cfif Arguments.Debug>
			<cfdump var="#Content#">
		</cfif>
		<cfset Content=ua.TableToArrays(Content)>
		<cfif Arguments.Debug>
			<cfdump var="#Content#">
		</cfif>
		<cfloop from="1" to="#ArrayLen(Content)#" index="i">
			<cfif IsArray(Content[i]) AND (ArrayLen(Content[i]) GTE 5)>
				<cfset Extra=ArrayLen(Content[i])-5>
				<cfset m=REFindNoCase('uid=([0-9]+)">([^<]+)<',Content[i][1],1,true)>
				<cfif ArrayLen(m.pos) EQ 3>
					<cfset QueryAddRow(Result)>
					<cfset QuerySetCell(Result,"UID",Mid(Content[i][1],m.pos[2],m.len[2]),Result.RecordCount)>
					<cfset QuerySetCell(Result,"Username",Mid(Content[i][1],m.pos[3],m.len[3]),Result.RecordCount)>
					<cfif Mid(Content[i][1],m.pos[3],m.len[3]) EQ Arguments.Username>
						<cfset PerfectMatch=Result.RecordCount>
					</cfif>
					<cfset QuerySetCell(Result,"Location",Content[i][3+Extra],Result.RecordCount)>
					<cfset QuerySetCell(Result,"JoinDate",Content[i][4+Extra],Result.RecordCount)>
					<cfset QuerySetCell(Result,"PostCount",Content[i][5+Extra],Result.RecordCount)>
					<cfset m=REFindNoCase("href='([^']+)'",Content[i][2+Extra],1,true)>
					<cfif ArrayLen(m.pos) EQ 2>
						<cfset QuerySetCell(Result,"HomePage",Mid(Content[i][2+Extra],m.pos[2],m.len[2]),Result.RecordCount)>
					</cfif>
					<cfset m=REFindNoCase("([^<]+)<br",Content[i][2+Extra],1,true)>
					<cfif ArrayLen(m.pos) EQ 2>
						<cfset QuerySetCell(Result,"NovelTitle",Mid(Content[i][2+Extra],m.pos[2],m.len[2]),Result.RecordCount)>
					</cfif>
					<cfif Content[i][1] CONTAINS "haloIcon.gif">
						<cfset QuerySetCell(Result,"Donor",true,Result.RecordCount)>
					<cfelse>
						<cfset QuerySetCell(Result,"Donor",false,Result.RecordCount)>
					</cfif>
				</cfif>
			</cfif>
		</cfloop>
		<cfif (PerfectMatch GT 0) AND (PerfectMatch LT Result.RecordCount) AND (Result.RecordCount GT 1)>
			<cfset Content=QueryNew(Result.ColumnList)>
			<cfset QueryAddRow(Content)>
			<cfloop list="#Result.ColumnList#" index="i">
				<cfset Content[i][1]=Result[i][PerfectMatch]>
			</cfloop>
			<cfset Result=Content>
		</cfif>
		<cfreturn Result>
	</cffunction>
	<cffunction name="Authenticate" access="remote" output="false" returntype="xml">
		<cfargument name="Username" type="string" required="true">
		<cfargument name="Password" type="string" required="true">
		<!--- TODO: Implement Method --->
		<cfreturn>
	</cffunction>
</cfcomponent>